Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-077.rds.xz")
summary(model)
SOM of size 25x25 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 1065343 objects.
Mean distance to the closest unit in the map: 0.06.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_dia_2k.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt          tmax       
 Length:1065343     Length:1065343     Min.   :  1.0   Min.   :-196.0  
 Class :character   Class :character   1st Qu.: 91.0   1st Qu.: 144.0  
 Mode  :character   Mode  :character   Median :183.0   Median : 201.0  
                                       Mean   :182.8   Mean   : 201.5  
                                       3rd Qu.:274.0   3rd Qu.: 263.0  
                                       Max.   :366.0   Max.   : 469.0  
      tmin             precip            nevada    prof_nieve       
 Min.   :-252.00   Min.   :   0.00   Min.   :0   Min.   :   0.0000  
 1st Qu.:  47.00   1st Qu.:   0.00   1st Qu.:0   1st Qu.:   0.0000  
 Median : 100.00   Median :   0.00   Median :0   Median :   0.0000  
 Mean   :  97.54   Mean   :  17.05   Mean   :0   Mean   :   0.6185  
 3rd Qu.: 153.00   3rd Qu.:   2.00   3rd Qu.:0   3rd Qu.:   0.0000  
 Max.   : 332.00   Max.   :3361.00   Max.   :0   Max.   :1240.0000  
    longitud        latitud           altitud    
 Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:39.47   1st Qu.: -4.850   1st Qu.:  47  
 Median :41.29   Median : -1.411   Median : 287  
 Mean   :40.10   Mean   : -2.391   Mean   : 486  
 3rd Qu.:42.22   3rd Qu.:  1.296   3rd Qu.: 691  
 Max.   :43.57   Max.   :  4.216   Max.   :2535  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
 433  445  750 2148 1474 1278  820  853 2197 2929 2998 3023 1891 2772 2260 1129 
  17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32 
1535 1452 1541 1588 2179 2042 2540 2629 2123  403  943 1344 1889 2148 2535 1933 
  33   34   35   36   37   38   39   40   41   42   43   44   45   46   47   48 
1566 1547 2406 2786 2651 2961 2733 1891 1871 2750 1617 1713 2102 1819 2635 3108 
  49   50   51   52   53   54   55   56   57   58   59   60   61   62   63   64 
2138 1458  667 1154 1527 2009 2768 3089 2836 2002 2269 2258 2662 2909 1560 2211 
  65   66   67   68   69   70   71   72   73   74   75   76   77   78   79   80 
1441 1798 2049 1705 2187 2672 2828  895 2156 2765 1360 1057  690 1309 1765 2042 
  81   82   83   84   85   86   87   88   89   90   91   92   93   94   95   96 
2535 2896 2173  650 1246 1590 2710 2639 2748 1995 2075 1957 2019 2813 3198 3045 
  97   98   99  100  101  102  103  104  105  106  107  108  109  110  111  112 
1845 3183 2566 1387  503  972  815 1590 1589 2059 2701 2183  716 1138 2503 1601 
 113  114  115  116  117  118  119  120  121  122  123  124  125  126  127  128 
2548 2570 2805 2502 2935 2554 2651 2994 2552 2841 1640 2340  535  277  701 1283 
 129  130  131  132  133  134  135  136  137  138  139  140  141  142  143  144 
1620 1761 2058 2245 1604 1410 1163 1330 1483 1837 1700 2548 2243 2641 2308 2188 
 145  146  147  148  149  150  151  152  153  154  155  156  157  158  159  160 
1672 2426 2892 2672 2204 1622  501 1037  545 1501 1373 1528 2224 1781 1397 1312 
 161  162  163  164  165  166  167  168  169  170  171  172  173  174  175  176 
2107  784 1516 2066 1794 2629 2843 2614 2664 1366 2647 2236 1658 1099  687  244 
 177  178  179  180  181  182  183  184  185  186  187  188  189  190  191  192 
 205  427  736  439 1125  998 1250  859 1917 2387 1162  867 1802 1947 2475 2200 
 193  194  195  196  197  198  199  200  201  202  203  204  205  206  207  208 
2851 2286 2226 1299 1634 1332 1063  913  165  472  613  885 1057 1164 1255 1384 
 209  210  211  212  213  214  215  216  217  218  219  220  221  222  223  224 
2339 2352 1987 1147  842  955 1545 2200 1977 2105 2588 1836  962 1265 2219 1917 
 225  226  227  228  229  230  231  232  233  234  235  236  237  238  239  240 
1372  122  271  387  454  861  965 1300  802 1891 1477 2423 1438 2330 1737 1334 
 241  242  243  244  245  246  247  248  249  250  251  252  253  254  255  256 
1659 1833 2292 2181 2573 1403 2009 2702 2676 1958   97  147  247  638  449 1090 
 257  258  259  260  261  262  263  264  265  266  267  268  269  270  271  272 
1420  909 1406 2247 1827 1399 1442 1888 1061 2070 1654 2343 2920 1502 1978 2820 
 273  274  275  276  277  278  279  280  281  282  283  284  285  286  287  288 
2661 2844 1995   22   43  203  334  371  625  903  859 1015 1501 2144 1516 1562 
 289  290  291  292  293  294  295  296  297  298  299  300  301  302  303  304 
2056 1895 1066 2282 1815 2963 1925 2045 1419 2685 2475 2546   98  135  252  464 
 305  306  307  308  309  310  311  312  313  314  315  316  317  318  319  320 
 575  575 1145  862 1457 1594  896 1882 2487 2054  916 1541 2444 2289 1796 2346 
 321  322  323  324  325  326  327  328  329  330  331  332  333  334  335  336 
1230 2388 2911 3230 2167   93  161  350  409  663  762 1065 1282 1036 1223 1489 
 337  338  339  340  341  342  343  344  345  346  347  348  349  350  351  352 
1838 2544 2091  882  819  799 2640 2863 2733 2737 2580 2316 3026 2922  172  464 
 353  354  355  356  357  358  359  360  361  362  363  364  365  366  367  368 
 631  798 1021  927 1555 1109  838  555 2109 2973 1877 1012  907 2213 2289 1435 
 369  370  371  372  373  374  375  376  377  378  379  380  381  382  383  384 
2494 2183 2456 2345 1681 2425 2596  189  362  510  605  784  693  941  860 1291 
 385  386  387  388  389  390  391  392  393  394  395  396  397  398  399  400 
 762 1269 1598 3138 1329 1741 1629  833 1756 2698 2826 2251 2041 2014 1768 2610 
 401  402  403  404  405  406  407  408  409  410  411  412  413  414  415  416 
 219  354  589  864 1014  812  611  981 1099 1192 1196 2547 2807  879 1938 2963 
 417  418  419  420  421  422  423  424  425  426  427  428  429  430  431  432 
2749 3185 2710 2948 2195 2064 1812 2047 2693  465  393  631  944 1086  860 1687 
 433  434  435  436  437  438  439  440  441  442  443  444  445  446  447  448 
1583 1321 1560 2167 1349 2163 1934 1167 1861 2889 3050 2754 2390 2078 2056 1193 
 449  450  451  452  453  454  455  456  457  458  459  460  461  462  463  464 
2053 1890  666 1079  690 1683 1124 1458 1487 1756  846 1464 2455 1272 1146 1388 
 465  466  467  468  469  470  471  472  473  474  475  476  477  478  479  480 
2265 2528 2869 2205 2750 2097 1600 1511 1956 1748 1364  621  494  948 1089 2014 
 481  482  483  484  485  486  487  488  489  490  491  492  493  494  495  496 
1378 1908 2809 1941 2078 1822 1629 2122 1000 1420 1582 2850 1656 1811 1849 1619 
 497  498  499  500  501  502  503  504  505  506  507  508  509  510  511  512 
1535 1921 2691 2596  712 1005  597  634 1651 2375 2822 1829 1061 1713 1055 1097 
 513  514  515  516  517  518  519  520  521  522  523  524  525  526  527  528 
1629 1897 2497 3349 3042 1330 1457 1343 1921 1639 2905 2167 1382  558  670  791 
 529  530  531  532  533  534  535  536  537  538  539  540  541  542  543  544 
1633 1791 1240 2974 2835 2677 2457  898 1547  978 2428 2516 2908 2279 2068 1136 
 545  546  547  548  549  550  551  552  553  554  555  556  557  558  559  560 
 711 1444 1920 2222 1737  976  278  599  750 1697 1555 2416 2496 2678 2475 1796 
 561  562  563  564  565  566  567  568  569  570  571  572  573  574  575  576 
 986 1337 2155 1845 2870 2897 2547 2677 1540 1802 1418 2266 2023 1771  409  301 
 577  578  579  580  581  582  583  584  585  586  587  588  589  590  591  592 
 385  955 1190 1141  882 2585 2146 1720 1381 1170 1990 2132 2763 2442 2952 3135 
 593  594  595  596  597  598  599  600  601  602  603  604  605  606  607  608 
3283 2789 2130 1953 1956 1669  556 1499  640  804 1179  628 1580 2000 1786 1813 
 609  610  611  612  613  614  615  616  617  618  619  620  621  622  623  624 
1327  662  780 1218 2184 2942 2998 2994 2811 2182 2800 2135 1485 1709 1655 1775 
 625 
1794 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 25*25;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
       fecha_cnt       tmax       tmin      precip
[1,] -0.08931473  0.7526296  0.7622684 -0.37764850
[2,] -0.91375475 -0.3122346 -0.3151137  0.02948056

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
fecha_cnt    precip      tmax      tmin 
0.9926052 0.9925619 0.9923844 0.9921381 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt        tmax             tmin             precip           nevada 
 Min.   :  1   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 45   1st Qu.:  99.0   1st Qu.:   3.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 93   Median : 136.0   Median :  36.00   Median :  0.00   Median :0  
 Mean   :142   Mean   : 130.8   Mean   :  34.32   Mean   : 31.63   Mean   :0  
 3rd Qu.:288   3rd Qu.: 169.0   3rd Qu.:  67.00   3rd Qu.: 20.00   3rd Qu.:0  
 Max.   :366   Max.   : 389.0   Max.   : 254.00   Max.   :795.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.71   1st Qu.: -4.010   1st Qu.: 143.0  
 Median :   0.000   Median :41.66   Median : -1.033   Median : 541.0  
 Mean   :   1.471   Mean   :41.12   Mean   : -1.620   Mean   : 692.5  
 3rd Qu.:   0.000   3rd Qu.:42.39   3rd Qu.:  1.401   3rd Qu.: 900.0  
 Max.   :1240.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   : 70.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:157.0   1st Qu.:210.0   1st Qu.:106.0   1st Qu.:  0.000   1st Qu.:0  
 Median :216.0   Median :250.0   Median :142.0   Median :  0.000   Median :0  
 Mean   :211.5   Mean   :251.6   Mean   :142.2   Mean   :  4.699   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:293.0   3rd Qu.:177.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332.0   Max.   :156.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud    
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.616   1st Qu.:  33  
 Median :   0.0000   Median :40.93   Median : -1.861   Median : 127  
 Mean   :   0.0145   Mean   :39.38   Mean   : -2.940   Mean   : 340  
 3rd Qu.:   0.0000   3rd Qu.:41.91   3rd Qu.:  1.165   3rd Qu.: 582  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt        tmax            tmin           precip           nevada 
 Min.   :  3   Min.   :-55.0   Min.   :-92.0   Min.   : 567.0   Min.   :0  
 1st Qu.:130   1st Qu.:119.0   1st Qu.: 72.0   1st Qu.: 664.2   1st Qu.:0  
 Median :273   Median :157.0   Median :110.0   Median : 762.0   Median :0  
 Mean   :226   Mean   :159.8   Mean   :103.1   Mean   : 841.7   Mean   :0  
 3rd Qu.:306   3rd Qu.:205.0   3rd Qu.:142.0   3rd Qu.: 925.0   3rd Qu.:0  
 Max.   :362   Max.   :344.0   Max.   :240.0   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud    
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:  0.000   1st Qu.:40.72   1st Qu.: -2.0392   1st Qu.:  35  
 Median :  0.000   Median :41.52   Median :  0.8856   Median : 179  
 Mean   :  1.026   Mean   :40.67   Mean   : -0.8400   Mean   : 487  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1053   3rd Qu.: 632  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 43.0   1st Qu.:  98.0   1st Qu.:   1.00   1st Qu.:  0.00  
 Median : 89.0   Median : 135.0   Median :  34.00   Median :  0.00  
 Mean   :137.7   Mean   : 129.1   Mean   :  30.04   Mean   : 13.94  
 3rd Qu.:277.0   3rd Qu.: 167.0   3rd Qu.:  62.00   3rd Qu.:  8.00  
 Max.   :366.0   Max.   : 318.0   Max.   : 205.00   Max.   :253.00  
     nevada    prof_nieve         longitud        latitud       
 Min.   :0   Min.   :   0.00   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:40.70   1st Qu.: -3.919  
 Median :0   Median :   0.00   Median :41.65   Median : -1.008  
 Mean   :0   Mean   :   1.41   Mean   :41.12   Mean   : -1.579  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.38   3rd Qu.:  1.401  
 Max.   :0   Max.   :1240.00   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 147.0  
 Median : 566.0  
 Mean   : 703.1  
 3rd Qu.: 916.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   : 70.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:157.0   1st Qu.:210.0   1st Qu.:106.0   1st Qu.:  0.000   1st Qu.:0  
 Median :216.0   Median :250.0   Median :142.0   Median :  0.000   Median :0  
 Mean   :211.5   Mean   :251.6   Mean   :142.2   Mean   :  4.699   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:293.0   3rd Qu.:177.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332.0   Max.   :156.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud    
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.616   1st Qu.:  33  
 Median :   0.0000   Median :40.93   Median : -1.861   Median : 127  
 Mean   :   0.0145   Mean   :39.38   Mean   : -2.940   Mean   : 340  
 3rd Qu.:   0.0000   3rd Qu.:41.91   3rd Qu.:  1.165   3rd Qu.: 582  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 84.0   Min.   :0  
 1st Qu.: 83.0   1st Qu.: 111.0   1st Qu.:  54.00   1st Qu.:170.0   1st Qu.:0  
 Median :224.0   Median : 150.0   Median :  92.00   Median :221.0   Median :0  
 Mean   :194.6   Mean   : 152.6   Mean   :  86.84   Mean   :248.9   Mean   :0  
 3rd Qu.:298.0   3rd Qu.: 201.0   3rd Qu.: 132.00   3rd Qu.:300.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 389.0   Max.   : 254.00   Max.   :795.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -5.616   1st Qu.:  59.0  
 Median :   0.000   Median :41.98   Median : -1.636   Median : 286.0  
 Mean   :   2.226   Mean   :41.15   Mean   : -2.124   Mean   : 562.5  
 3rd Qu.:   0.000   3rd Qu.:42.59   3rd Qu.:  1.512   3rd Qu.: 785.0  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt        tmax            tmin           precip           nevada 
 Min.   :  3   Min.   :-55.0   Min.   :-92.0   Min.   : 567.0   Min.   :0  
 1st Qu.:130   1st Qu.:119.0   1st Qu.: 72.0   1st Qu.: 664.2   1st Qu.:0  
 Median :273   Median :157.0   Median :110.0   Median : 762.0   Median :0  
 Mean   :226   Mean   :159.8   Mean   :103.1   Mean   : 841.7   Mean   :0  
 3rd Qu.:306   3rd Qu.:205.0   3rd Qu.:142.0   3rd Qu.: 925.0   3rd Qu.:0  
 Max.   :362   Max.   :344.0   Max.   :240.0   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud    
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:  0.000   1st Qu.:40.72   1st Qu.: -2.0392   1st Qu.:  35  
 Median :  0.000   Median :41.52   Median :  0.8856   Median : 179  
 Mean   :  1.026   Mean   :40.67   Mean   : -0.8400   Mean   : 487  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1053   3rd Qu.: 632  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax           tmin             precip           nevada 
 Min.   :187.0   Min.   :-158   Min.   :-240.00   Min.   :  0.00   Min.   :0  
 1st Qu.:320.0   1st Qu.:  81   1st Qu.: -10.00   1st Qu.:  0.00   1st Qu.:0  
 Median :337.0   Median : 112   Median :  17.00   Median :  0.00   Median :0  
 Mean   :333.2   Mean   : 108   Mean   :  11.15   Mean   :  9.39   Mean   :0  
 3rd Qu.:352.0   3rd Qu.: 140   3rd Qu.:  38.00   3rd Qu.:  2.00   3rd Qu.:0  
 Max.   :366.0   Max.   : 244   Max.   :  98.00   Max.   :253.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :   0.000   Min.   :28.31   Min.   :-16.4992   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.84   1st Qu.: -3.7642   1st Qu.: 333.0  
 Median :   0.000   Median :41.68   Median :  0.4483   Median : 667.0  
 Mean   :   0.847   Mean   :41.30   Mean   : -1.2073   Mean   : 831.5  
 3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.5117   3rd Qu.:1005.0  
 Max.   :1240.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   : 70.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:157.0   1st Qu.:210.0   1st Qu.:106.0   1st Qu.:  0.000   1st Qu.:0  
 Median :216.0   Median :250.0   Median :142.0   Median :  0.000   Median :0  
 Mean   :211.5   Mean   :251.6   Mean   :142.2   Mean   :  4.699   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:293.0   3rd Qu.:177.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332.0   Max.   :156.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud    
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.616   1st Qu.:  33  
 Median :   0.0000   Median :40.93   Median : -1.861   Median : 127  
 Mean   :   0.0145   Mean   :39.38   Mean   : -2.940   Mean   : 340  
 3rd Qu.:   0.0000   3rd Qu.:41.91   3rd Qu.:  1.165   3rd Qu.: 582  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 84.0   Min.   :0  
 1st Qu.: 83.0   1st Qu.: 111.0   1st Qu.:  54.00   1st Qu.:170.0   1st Qu.:0  
 Median :224.0   Median : 150.0   Median :  92.00   Median :221.0   Median :0  
 Mean   :194.6   Mean   : 152.6   Mean   :  86.84   Mean   :248.9   Mean   :0  
 3rd Qu.:298.0   3rd Qu.: 201.0   3rd Qu.: 132.00   3rd Qu.:300.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 389.0   Max.   : 254.00   Max.   :795.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -5.616   1st Qu.:  59.0  
 Median :   0.000   Median :41.98   Median : -1.636   Median : 286.0  
 Mean   :   2.226   Mean   :41.15   Mean   : -2.124   Mean   : 562.5  
 3rd Qu.:   0.000   3rd Qu.:42.59   3rd Qu.:  1.512   3rd Qu.: 785.0  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt        tmax            tmin           precip           nevada 
 Min.   :  3   Min.   :-55.0   Min.   :-92.0   Min.   : 567.0   Min.   :0  
 1st Qu.:130   1st Qu.:119.0   1st Qu.: 72.0   1st Qu.: 664.2   1st Qu.:0  
 Median :273   Median :157.0   Median :110.0   Median : 762.0   Median :0  
 Mean   :226   Mean   :159.8   Mean   :103.1   Mean   : 841.7   Mean   :0  
 3rd Qu.:306   3rd Qu.:205.0   3rd Qu.:142.0   3rd Qu.: 925.0   3rd Qu.:0  
 Max.   :362   Max.   :344.0   Max.   :240.0   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud    
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:  0.000   1st Qu.:40.72   1st Qu.: -2.0392   1st Qu.:  35  
 Median :  0.000   Median :41.52   Median :  0.8856   Median : 179  
 Mean   :  1.026   Mean   :40.67   Mean   : -0.8400   Mean   : 487  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.1053   3rd Qu.: 632  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin             precip      
 Min.   :  1.00   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 32.00   1st Qu.: 107.0   1st Qu.:   6.00   1st Qu.:  0.00  
 Median : 64.00   Median : 144.0   Median :  42.00   Median :  0.00  
 Mean   : 70.16   Mean   : 136.3   Mean   :  36.57   Mean   : 15.51  
 3rd Qu.:102.00   3rd Qu.: 174.0   3rd Qu.:  70.00   3rd Qu.: 12.00  
 Max.   :249.00   Max.   : 318.0   Max.   : 205.00   Max.   :218.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.65   Median : -1.169  
 Mean   :0   Mean   :   1.604   Mean   :41.06   Mean   : -1.707  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.384  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 112.0  
 Median : 515.0  
 Mean   : 658.7  
 3rd Qu.: 890.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax           tmin             precip           nevada 
 Min.   :187.0   Min.   :-158   Min.   :-240.00   Min.   :  0.00   Min.   :0  
 1st Qu.:320.0   1st Qu.:  81   1st Qu.: -10.00   1st Qu.:  0.00   1st Qu.:0  
 Median :337.0   Median : 112   Median :  17.00   Median :  0.00   Median :0  
 Mean   :333.2   Mean   : 108   Mean   :  11.15   Mean   :  9.39   Mean   :0  
 3rd Qu.:352.0   3rd Qu.: 140   3rd Qu.:  38.00   3rd Qu.:  2.00   3rd Qu.:0  
 Max.   :366.0   Max.   : 244   Max.   :  98.00   Max.   :253.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :   0.000   Min.   :28.31   Min.   :-16.4992   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.84   1st Qu.: -3.7642   1st Qu.: 333.0  
 Median :   0.000   Median :41.68   Median :  0.4483   Median : 667.0  
 Mean   :   0.847   Mean   :41.30   Mean   : -1.2073   Mean   : 831.5  
 3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.5117   3rd Qu.:1005.0  
 Max.   :1240.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   : 70.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:157.0   1st Qu.:210.0   1st Qu.:106.0   1st Qu.:  0.000   1st Qu.:0  
 Median :216.0   Median :250.0   Median :142.0   Median :  0.000   Median :0  
 Mean   :211.5   Mean   :251.6   Mean   :142.2   Mean   :  4.699   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:293.0   3rd Qu.:177.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332.0   Max.   :156.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud    
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.616   1st Qu.:  33  
 Median :   0.0000   Median :40.93   Median : -1.861   Median : 127  
 Mean   :   0.0145   Mean   :39.38   Mean   : -2.940   Mean   : 340  
 3rd Qu.:   0.0000   3rd Qu.:41.91   3rd Qu.:  1.165   3rd Qu.: 582  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 84.0   Min.   :0  
 1st Qu.: 83.0   1st Qu.: 111.0   1st Qu.:  54.00   1st Qu.:170.0   1st Qu.:0  
 Median :224.0   Median : 150.0   Median :  92.00   Median :221.0   Median :0  
 Mean   :194.6   Mean   : 152.6   Mean   :  86.84   Mean   :248.9   Mean   :0  
 3rd Qu.:298.0   3rd Qu.: 201.0   3rd Qu.: 132.00   3rd Qu.:300.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 389.0   Max.   : 254.00   Max.   :795.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -5.616   1st Qu.:  59.0  
 Median :   0.000   Median :41.98   Median : -1.636   Median : 286.0  
 Mean   :   2.226   Mean   :41.15   Mean   : -2.124   Mean   : 562.5  
 3rd Qu.:   0.000   3rd Qu.:42.59   3rd Qu.:  1.512   3rd Qu.: 785.0  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   :  3.0   Min.   :-55.0   Min.   :-92.0   Min.   : 567.0   Min.   :0  
 1st Qu.:131.0   1st Qu.:121.8   1st Qu.: 74.0   1st Qu.: 657.0   1st Qu.:0  
 Median :272.0   Median :158.0   Median :111.0   Median : 737.0   Median :0  
 Mean   :226.5   Mean   :162.0   Mean   :104.2   Mean   : 769.8   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:207.2   3rd Qu.:142.0   3rd Qu.: 854.0   3rd Qu.:0  
 Max.   :362.0   Max.   :344.0   Max.   :240.0   Max.   :1166.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.80   1st Qu.: -2.3308   1st Qu.:  35.0  
 Median :  0.0000   Median :41.57   Median :  1.0256   Median : 176.0  
 Mean   :  0.3533   Mean   :40.78   Mean   : -0.8044   Mean   : 470.9  
 3rd Qu.:  0.0000   3rd Qu.:42.26   3rd Qu.:  2.1053   3rd Qu.: 594.0  
 Max.   :170.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin            precip         nevada 
 Min.   : 19.00   Min.   :  0.0   Min.   :-41.00   Min.   :1125   Min.   :0  
 1st Qu.: 91.25   1st Qu.: 88.5   1st Qu.: 49.25   1st Qu.:1251   1st Qu.:0  
 Median :283.50   Median :141.5   Median :103.50   Median :1354   Median :0  
 Mean   :222.32   Mean   :140.9   Mean   : 94.06   Mean   :1456   Mean   :0  
 3rd Qu.:306.75   3rd Qu.:192.8   3rd Qu.:140.75   3rd Qu.:1563   3rd Qu.:0  
 Max.   :354.00   Max.   :282.0   Max.   :202.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.48   1st Qu.:  0.0714   1st Qu.:  35.0  
 Median :  0.000   Median :40.82   Median :  0.4914   Median : 262.5  
 Mean   :  6.778   Mean   :39.74   Mean   : -1.1442   Mean   : 624.7  
 3rd Qu.:  0.000   3rd Qu.:41.84   3rd Qu.:  1.9656   3rd Qu.:1055.0  
 Max.   :559.000   Max.   :43.57   Max.   :  3.0967   Max.   :2519.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax             tmin             precip      
 Min.   :  1.00   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 32.00   1st Qu.: 107.0   1st Qu.:   6.00   1st Qu.:  0.00  
 Median : 64.00   Median : 144.0   Median :  42.00   Median :  0.00  
 Mean   : 70.16   Mean   : 136.3   Mean   :  36.57   Mean   : 15.51  
 3rd Qu.:102.00   3rd Qu.: 174.0   3rd Qu.:  70.00   3rd Qu.: 12.00  
 Max.   :249.00   Max.   : 318.0   Max.   : 205.00   Max.   :218.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.65   Median : -1.169  
 Mean   :0   Mean   :   1.604   Mean   :41.06   Mean   : -1.707  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.384  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 112.0  
 Median : 515.0  
 Mean   : 658.7  
 3rd Qu.: 890.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax           tmin             precip           nevada 
 Min.   :187.0   Min.   :-158   Min.   :-240.00   Min.   :  0.00   Min.   :0  
 1st Qu.:320.0   1st Qu.:  81   1st Qu.: -10.00   1st Qu.:  0.00   1st Qu.:0  
 Median :337.0   Median : 112   Median :  17.00   Median :  0.00   Median :0  
 Mean   :333.2   Mean   : 108   Mean   :  11.15   Mean   :  9.39   Mean   :0  
 3rd Qu.:352.0   3rd Qu.: 140   3rd Qu.:  38.00   3rd Qu.:  2.00   3rd Qu.:0  
 Max.   :366.0   Max.   : 244   Max.   :  98.00   Max.   :253.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :   0.000   Min.   :28.31   Min.   :-16.4992   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.84   1st Qu.: -3.7642   1st Qu.: 333.0  
 Median :   0.000   Median :41.68   Median :  0.4483   Median : 667.0  
 Mean   :   0.847   Mean   :41.30   Mean   : -1.2073   Mean   : 831.5  
 3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.5117   3rd Qu.:1005.0  
 Max.   :1240.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :174.0   Min.   : 70.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:265.0   1st Qu.:180.0   1st Qu.: 86.0   1st Qu.:  0.000   1st Qu.:0  
 Median :289.0   Median :220.0   Median :114.0   Median :  0.000   Median :0  
 Mean   :290.5   Mean   :217.5   Mean   :117.5   Mean   :  7.703   Mean   :0  
 3rd Qu.:316.0   3rd Qu.:256.0   3rd Qu.:144.0   3rd Qu.:  1.000   3rd Qu.:0  
 Max.   :366.0   Max.   :358.0   Max.   :250.0   Max.   :156.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:38.88   1st Qu.: -5.600   1st Qu.:  35.0  
 Median :   0.000   Median :41.19   Median : -1.787   Median : 192.0  
 Mean   :   0.027   Mean   :39.85   Mean   : -2.723   Mean   : 408.2  
 3rd Qu.:   0.000   3rd Qu.:42.18   3rd Qu.:  1.272   3rd Qu.: 639.0  
 Max.   :1039.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :122.0   Min.   : 10.0   Min.   :  0.000   Min.   :0  
 1st Qu.:130.0   1st Qu.:229.0   1st Qu.:123.0   1st Qu.:  0.000   1st Qu.:0  
 Median :175.0   Median :271.0   Median :159.0   Median :  0.000   Median :0  
 Mean   :166.9   Mean   :270.8   Mean   :156.2   Mean   :  3.003   Mean   :0  
 3rd Qu.:213.0   3rd Qu.:310.0   3rd Qu.:189.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :344.0   Max.   :469.0   Max.   :332.0   Max.   :147.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.79   1st Qu.: -5.649   1st Qu.:  32.0  
 Median :   0.0000   Median :40.71   Median : -1.861   Median :  91.0  
 Mean   :   0.0075   Mean   :39.12   Mean   : -3.062   Mean   : 301.4  
 3rd Qu.:   0.0000   3rd Qu.:41.68   3rd Qu.:  1.039   3rd Qu.: 534.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt        tmax             tmin             precip          nevada 
 Min.   :  1   Min.   :-124.0   Min.   :-186.00   Min.   :230.0   Min.   :0  
 1st Qu.: 78   1st Qu.:  75.0   1st Qu.:  19.00   1st Qu.:342.0   1st Qu.:0  
 Median :155   Median : 124.0   Median :  68.00   Median :397.0   Median :0  
 Mean   :185   Mean   : 113.1   Mean   :  57.03   Mean   :414.7   Mean   :0  
 3rd Qu.:307   3rd Qu.: 155.0   3rd Qu.: 100.00   3rd Qu.:480.0   3rd Qu.:0  
 Max.   :366   Max.   : 369.0   Max.   : 241.00   Max.   :795.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:41.15   1st Qu.: -4.0103   1st Qu.:  98.0  
 Median :  0.000   Median :42.18   Median :  0.7433   Median : 427.0  
 Mean   :  4.701   Mean   :41.39   Mean   : -1.3289   Mean   : 820.7  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.7150   3rd Qu.:1572.0  
 Max.   :899.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 84.0   Min.   :0  
 1st Qu.: 85.0   1st Qu.: 119.0   1st Qu.:  60.00   1st Qu.:161.0   1st Qu.:0  
 Median :230.0   Median : 158.0   Median :  98.00   Median :200.0   Median :0  
 Mean   :196.8   Mean   : 161.7   Mean   :  93.72   Mean   :210.6   Mean   :0  
 3rd Qu.:295.0   3rd Qu.: 211.0   3rd Qu.: 138.00   3rd Qu.:250.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 389.0   Max.   : 254.00   Max.   :480.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.71   1st Qu.: -5.661   1st Qu.:  58.0  
 Median :   0.000   Median :41.91   Median : -1.787   Median : 261.0  
 Mean   :   1.655   Mean   :41.09   Mean   : -2.307   Mean   : 502.9  
 3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.401   3rd Qu.: 687.0  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   :  3.0   Min.   :-55.0   Min.   :-92.0   Min.   : 567.0   Min.   :0  
 1st Qu.:131.0   1st Qu.:121.8   1st Qu.: 74.0   1st Qu.: 657.0   1st Qu.:0  
 Median :272.0   Median :158.0   Median :111.0   Median : 737.0   Median :0  
 Mean   :226.5   Mean   :162.0   Mean   :104.2   Mean   : 769.8   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:207.2   3rd Qu.:142.0   3rd Qu.: 854.0   3rd Qu.:0  
 Max.   :362.0   Max.   :344.0   Max.   :240.0   Max.   :1166.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.80   1st Qu.: -2.3308   1st Qu.:  35.0  
 Median :  0.0000   Median :41.57   Median :  1.0256   Median : 176.0  
 Mean   :  0.3533   Mean   :40.78   Mean   : -0.8044   Mean   : 470.9  
 3rd Qu.:  0.0000   3rd Qu.:42.26   3rd Qu.:  2.1053   3rd Qu.: 594.0  
 Max.   :170.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin            precip         nevada 
 Min.   : 19.00   Min.   :  0.0   Min.   :-41.00   Min.   :1125   Min.   :0  
 1st Qu.: 91.25   1st Qu.: 88.5   1st Qu.: 49.25   1st Qu.:1251   1st Qu.:0  
 Median :283.50   Median :141.5   Median :103.50   Median :1354   Median :0  
 Mean   :222.32   Mean   :140.9   Mean   : 94.06   Mean   :1456   Mean   :0  
 3rd Qu.:306.75   3rd Qu.:192.8   3rd Qu.:140.75   3rd Qu.:1563   3rd Qu.:0  
 Max.   :354.00   Max.   :282.0   Max.   :202.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.48   1st Qu.:  0.0714   1st Qu.:  35.0  
 Median :  0.000   Median :40.82   Median :  0.4914   Median : 262.5  
 Mean   :  6.778   Mean   :39.74   Mean   : -1.1442   Mean   : 624.7  
 3rd Qu.:  0.000   3rd Qu.:41.84   3rd Qu.:  1.9656   3rd Qu.:1055.0  
 Max.   :559.000   Max.   :43.57   Max.   :  3.0967   Max.   :2519.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax             tmin             precip      
 Min.   :  1.00   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 32.00   1st Qu.: 107.0   1st Qu.:   6.00   1st Qu.:  0.00  
 Median : 64.00   Median : 144.0   Median :  42.00   Median :  0.00  
 Mean   : 70.16   Mean   : 136.3   Mean   :  36.57   Mean   : 15.51  
 3rd Qu.:102.00   3rd Qu.: 174.0   3rd Qu.:  70.00   3rd Qu.: 12.00  
 Max.   :249.00   Max.   : 318.0   Max.   : 205.00   Max.   :218.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.65   Median : -1.169  
 Mean   :0   Mean   :   1.604   Mean   :41.06   Mean   : -1.707  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.384  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 112.0  
 Median : 515.0  
 Mean   : 658.7  
 3rd Qu.: 890.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax           tmin             precip           nevada 
 Min.   :187.0   Min.   :-158   Min.   :-240.00   Min.   :  0.00   Min.   :0  
 1st Qu.:320.0   1st Qu.:  81   1st Qu.: -10.00   1st Qu.:  0.00   1st Qu.:0  
 Median :337.0   Median : 112   Median :  17.00   Median :  0.00   Median :0  
 Mean   :333.2   Mean   : 108   Mean   :  11.15   Mean   :  9.39   Mean   :0  
 3rd Qu.:352.0   3rd Qu.: 140   3rd Qu.:  38.00   3rd Qu.:  2.00   3rd Qu.:0  
 Max.   :366.0   Max.   : 244   Max.   :  98.00   Max.   :253.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :   0.000   Min.   :28.31   Min.   :-16.4992   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.84   1st Qu.: -3.7642   1st Qu.: 333.0  
 Median :   0.000   Median :41.68   Median :  0.4483   Median : 667.0  
 Mean   :   0.847   Mean   :41.30   Mean   : -1.2073   Mean   : 831.5  
 3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.5117   3rd Qu.:1005.0  
 Max.   :1240.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :174.0   Min.   : 70.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:265.0   1st Qu.:180.0   1st Qu.: 86.0   1st Qu.:  0.000   1st Qu.:0  
 Median :289.0   Median :220.0   Median :114.0   Median :  0.000   Median :0  
 Mean   :290.5   Mean   :217.5   Mean   :117.5   Mean   :  7.703   Mean   :0  
 3rd Qu.:316.0   3rd Qu.:256.0   3rd Qu.:144.0   3rd Qu.:  1.000   3rd Qu.:0  
 Max.   :366.0   Max.   :358.0   Max.   :250.0   Max.   :156.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:38.88   1st Qu.: -5.600   1st Qu.:  35.0  
 Median :   0.000   Median :41.19   Median : -1.787   Median : 192.0  
 Mean   :   0.027   Mean   :39.85   Mean   : -2.723   Mean   : 408.2  
 3rd Qu.:   0.000   3rd Qu.:42.18   3rd Qu.:  1.272   3rd Qu.: 639.0  
 Max.   :1039.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 81.0   Min.   :226.0   Min.   : 76.0   Min.   : 0.0000   Min.   :0  
 1st Qu.:189.0   1st Qu.:292.0   1st Qu.:170.0   1st Qu.: 0.0000   1st Qu.:0  
 Median :211.0   Median :314.0   Median :191.0   Median : 0.0000   Median :0  
 Mean   :210.8   Mean   :316.1   Mean   :190.6   Mean   : 0.5975   Mean   :0  
 3rd Qu.:233.0   3rd Qu.:339.0   3rd Qu.:212.0   3rd Qu.: 0.0000   3rd Qu.:0  
 Max.   :344.0   Max.   :469.0   Max.   :332.0   Max.   :58.0000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :0.00e+00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:0.00e+00   1st Qu.:37.84   1st Qu.: -4.846   1st Qu.:  33.0  
 Median :0.00e+00   Median :40.47   Median : -1.229   Median : 108.0  
 Mean   :1.14e-04   Mean   :39.20   Mean   : -2.449   Mean   : 283.8  
 3rd Qu.:0.00e+00   3rd Qu.:41.57   3rd Qu.:  1.168   3rd Qu.: 541.0  
 Max.   :2.00e+01   Max.   :43.57   Max.   :  4.216   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :122.0   Min.   : 10.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 98.0   1st Qu.:209.0   1st Qu.:105.0   1st Qu.:  0.000   1st Qu.:0  
 Median :137.0   Median :234.0   Median :128.0   Median :  0.000   Median :0  
 Mean   :132.2   Mean   :235.2   Mean   :129.1   Mean   :  4.898   Mean   :0  
 3rd Qu.:168.0   3rd Qu.:260.0   3rd Qu.:154.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :340.0   Max.   :407.0   Max.   :265.0   Max.   :147.000   Max.   :0  
   prof_nieve           longitud        latitud            altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.78   1st Qu.: -5.8792   1st Qu.:  32.0  
 Median :   0.0000   Median :40.84   Median : -2.3567   Median :  90.0  
 Mean   :   0.0133   Mean   :39.05   Mean   : -3.5455   Mean   : 315.3  
 3rd Qu.:   0.0000   3rd Qu.:42.07   3rd Qu.:  0.8856   3rd Qu.: 534.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt        tmax             tmin             precip          nevada 
 Min.   :  1   Min.   :-124.0   Min.   :-186.00   Min.   :230.0   Min.   :0  
 1st Qu.: 78   1st Qu.:  75.0   1st Qu.:  19.00   1st Qu.:342.0   1st Qu.:0  
 Median :155   Median : 124.0   Median :  68.00   Median :397.0   Median :0  
 Mean   :185   Mean   : 113.1   Mean   :  57.03   Mean   :414.7   Mean   :0  
 3rd Qu.:307   3rd Qu.: 155.0   3rd Qu.: 100.00   3rd Qu.:480.0   3rd Qu.:0  
 Max.   :366   Max.   : 369.0   Max.   : 241.00   Max.   :795.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:41.15   1st Qu.: -4.0103   1st Qu.:  98.0  
 Median :  0.000   Median :42.18   Median :  0.7433   Median : 427.0  
 Mean   :  4.701   Mean   :41.39   Mean   : -1.3289   Mean   : 820.7  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.7150   3rd Qu.:1572.0  
 Max.   :899.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 84.0   Min.   :0  
 1st Qu.: 85.0   1st Qu.: 119.0   1st Qu.:  60.00   1st Qu.:161.0   1st Qu.:0  
 Median :230.0   Median : 158.0   Median :  98.00   Median :200.0   Median :0  
 Mean   :196.8   Mean   : 161.7   Mean   :  93.72   Mean   :210.6   Mean   :0  
 3rd Qu.:295.0   3rd Qu.: 211.0   3rd Qu.: 138.00   3rd Qu.:250.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 389.0   Max.   : 254.00   Max.   :480.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.71   1st Qu.: -5.661   1st Qu.:  58.0  
 Median :   0.000   Median :41.91   Median : -1.787   Median : 261.0  
 Mean   :   1.655   Mean   :41.09   Mean   : -2.307   Mean   : 502.9  
 3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.401   3rd Qu.: 687.0  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   :  3.0   Min.   :-55.0   Min.   :-92.0   Min.   : 567.0   Min.   :0  
 1st Qu.:131.0   1st Qu.:121.8   1st Qu.: 74.0   1st Qu.: 657.0   1st Qu.:0  
 Median :272.0   Median :158.0   Median :111.0   Median : 737.0   Median :0  
 Mean   :226.5   Mean   :162.0   Mean   :104.2   Mean   : 769.8   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:207.2   3rd Qu.:142.0   3rd Qu.: 854.0   3rd Qu.:0  
 Max.   :362.0   Max.   :344.0   Max.   :240.0   Max.   :1166.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.80   1st Qu.: -2.3308   1st Qu.:  35.0  
 Median :  0.0000   Median :41.57   Median :  1.0256   Median : 176.0  
 Mean   :  0.3533   Mean   :40.78   Mean   : -0.8044   Mean   : 470.9  
 3rd Qu.:  0.0000   3rd Qu.:42.26   3rd Qu.:  2.1053   3rd Qu.: 594.0  
 Max.   :170.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin            precip         nevada 
 Min.   : 19.00   Min.   :  0.0   Min.   :-41.00   Min.   :1125   Min.   :0  
 1st Qu.: 91.25   1st Qu.: 88.5   1st Qu.: 49.25   1st Qu.:1251   1st Qu.:0  
 Median :283.50   Median :141.5   Median :103.50   Median :1354   Median :0  
 Mean   :222.32   Mean   :140.9   Mean   : 94.06   Mean   :1456   Mean   :0  
 3rd Qu.:306.75   3rd Qu.:192.8   3rd Qu.:140.75   3rd Qu.:1563   3rd Qu.:0  
 Max.   :354.00   Max.   :282.0   Max.   :202.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.48   1st Qu.:  0.0714   1st Qu.:  35.0  
 Median :  0.000   Median :40.82   Median :  0.4914   Median : 262.5  
 Mean   :  6.778   Mean   :39.74   Mean   : -1.1442   Mean   : 624.7  
 3rd Qu.:  0.000   3rd Qu.:41.84   3rd Qu.:  1.9656   3rd Qu.:1055.0  
 Max.   :559.000   Max.   :43.57   Max.   :  3.0967   Max.   :2519.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   :  1.00   Min.   : 31.0   Min.   :-55.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 40.00   1st Qu.:132.0   1st Qu.: 31.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 74.00   Median :158.0   Median : 56.00   Median :  0.00   Median :0  
 Mean   : 77.15   Mean   :156.8   Mean   : 55.55   Mean   : 14.43   Mean   :0  
 3rd Qu.:109.00   3rd Qu.:182.0   3rd Qu.: 78.00   3rd Qu.:  9.00   3rd Qu.:0  
 Max.   :249.00   Max.   :318.0   Max.   :205.00   Max.   :218.00   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:40.41   1st Qu.: -4.488   1st Qu.:  81.0  
 Median :   0.0000   Median :41.53   Median : -1.411   Median : 370.0  
 Mean   :   0.2762   Mean   :40.90   Mean   : -1.895   Mean   : 516.7  
 3rd Qu.:   0.0000   3rd Qu.:42.33   3rd Qu.:  1.366   3rd Qu.: 775.0  
 Max.   :1151.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt           tmax              tmin             precip      
 Min.   :  1.00   Min.   :-196.00   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 20.00   1st Qu.:  44.00   1st Qu.: -41.00   1st Qu.:  0.00  
 Median : 40.50   Median :  79.00   Median : -18.00   Median :  0.00  
 Mean   : 48.68   Mean   :  73.58   Mean   : -21.79   Mean   : 18.86  
 3rd Qu.: 67.00   3rd Qu.: 107.00   3rd Qu.:   0.00   3rd Qu.: 25.00  
 Max.   :228.00   Max.   : 216.00   Max.   : 101.00   Max.   :161.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.95   1st Qu.: -3.723  
 Median :0   Median :   0.000   Median :42.05   Median :  0.635  
 Mean   :0   Mean   :   5.687   Mean   :41.54   Mean   : -1.130  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.47   3rd Qu.:  1.433  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.216  
    altitud    
 Min.   :   1  
 1st Qu.: 534  
 Median : 852  
 Mean   :1095  
 3rd Qu.:1894  
 Max.   :2535  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBkaWEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiA3NwoqIERlc2NyaXBjacOzbjogCiogRnJlY3VlbmNpYTogZGlhCiogVmFyaWFibGVzOiBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcAoqIERpbWVuc2lvbmVzIGRlbCBtYXBhOiAyNSwyNQoqIEl0ZXJhY2lvbmVzOiAxMDAwCiogUGFyw6FtZXRyb3MgYWRpY2lvbmFsZXM6IAoKYGBge3J9CnNvdXJjZSgiLi4vLi4vbGliL3NvbS11dGlscy5SIikKc291cmNlKCIuLi8uLi9saWIvbWFwcy11dGlscy5SIikKYGBgCgojIENhcmdhIGRlbCBtb2RlbG8gZGVzZGUgZGlzY28KCmBgYHtyfQptcHIuc2V0X2Jhc2VfcGF0aF9hbmFseXNpcygpCm1vZGVsIDwtIG1wci5sb2FkX21vZGVsKCJzb20tMDc3LnJkcy54eiIpCnN1bW1hcnkobW9kZWwpCmBgYAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNoYW5nZXMiKQpgYGAKCiMgQ2FyZ2EgZGVsIGRhdGFzZXQgZGUgZW50cmFkYQoKYGBge3J9CmRmIDwtIG1wci5sb2FkX2RhdGEoImRhdG9zX2RpYV8yay5jc3YueHoiKQpgYGAKCmBgYHtyfQpkZgpgYGAKCmBgYHtyfQpzdW1tYXJ5KGRmKQpgYGAKCiMgQ2FyZ2EgZGUgbG9zIG1hcGFzCgpgYGB7cn0Kd29ybGQgPC0gbmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikKc3BhaW4gPC0gc3Vic2V0KHdvcmxkLCBhZG1pbiA9PSAiU3BhaW4iKQpgYGAKCiMgTWFwYSBkZSBkZW5zaWRhZAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNvdW50Iiwgc2hhcGUgPSAic3RyYWlnaHQiLCBwYWxldHRlLm5hbWUgPSBtcHIuZGVncmFkZS5ibGV1KQpgYGAKCk7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2VsZGE6CgpgYGB7cn0KbmIgPC0gdGFibGUobW9kZWwkdW5pdC5jbGFzc2lmKQpwcmludChuYikKYGBgCkNvbXByb2JhY2nDs24gZGUgbm9kb3MgdmFjw61vczoKCmBgYHtyfQpkaW1fbW9kZWwgPC0gMjUqMjU7Cmxlbl9uYiA9IGxlbmd0aChuYik7CmVtcHR5X25vZGVzIDwtIGRpbV9tb2RlbCAhPSBsZW5fbmI7CmlmIChlbXB0eV9ub2RlcykgewogIHByaW50KHBhc3RlKCJbV2FybmluZ10gRXhpc3RlbiBub2RvcyB2YWPDrW9zOiAiLCBsZW5fbmIsICIvIiwgZGltX21vZGVsKSkKfQpgYGAKCiMgTWFwYSBkZSBkaXN0YW5jaWEgZW50cmUgdmVjaW5vcwoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImRpc3QubmVpZ2hib3VycyIsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIEluZmx1ZW5jaWEgZGUgbGFzIHZhcmlhYmxlcwoKYGBge3J9Cm1vZGVsX2NvbG5hbWVzID0gYygiZmVjaGFfY250IiwgInRtYXgiLCAidG1pbiIsICJwcmVjaXAiKQptb2RlbF9uY29sID0gbGVuZ3RoKG1vZGVsX2NvbG5hbWVzKQpgYGAKCiMjIE1hcGEgZGUgdmFyaWFibGVzLgoKYGBge3J9CnBsb3QobW9kZWwsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIyBNYXBhIGRlIGNhbG9yIHBvciB2YXJpYWJsZQoKYGBge3J9CnBhcihtZnJvdz1jKDMsNCkpCmZvciAoaiBpbiAxOm1vZGVsX25jb2wpIHsKICBwbG90KG1vZGVsLCB0eXBlPSJwcm9wZXJ0eSIsIHByb3BlcnR5PWdldENvZGVzKG1vZGVsLDEpWyxqXSwKICAgIHBhbGV0dGUubmFtZT1tcHIuY29vbEJsdWVIb3RSZWQsCiAgICBtYWluPW1vZGVsX2NvbG5hbWVzW2pdLAogICAgY2V4PTAuNSwgc2hhcGUgPSAic3RyYWlnaHQiKQp9CmBgYAoKIyMgQ29ycmVsYWNpw7NuIHBhcmEgY2FkYSBjb2x1bW5hIGRlbCB2ZWN0b3IgZGUgbm9kb3MKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgY29yIDwtIGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLCAyLCBtcHIud2VpZ2h0ZWQuY29ycmVsYXRpb24sIHc9bmIsIHNvbT1tb2RlbCkKICBwcmludChjb3IpCn0KYGBgCgpSZXByZXNlbnRhY2nDs24gZGUgY2FkYSB2YXJpYWJsZSBlbiB1biBtYXBhIGRlIGZhY3RvcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwYXIobWZyb3c9YygxLDEpKQogIHBsb3QoY29yWzEsXSwgY29yWzIsXSwgeGxpbT1jKC0xLDEpLCB5bGltPWMoLTEsMSksIHR5cGU9Im4iKQogIGxpbmVzKGMoLTEsMSksYygwLDApKQogIGxpbmVzKGMoMCwwKSxjKC0xLDEpKQogIHRleHQoY29yWzEsXSwgY29yWzIsXSwgbGFiZWxzPW1vZGVsX2NvbG5hbWVzLCBjZXg9MC43NSkKICBzeW1ib2xzKDAsMCxjaXJjbGVzPTEsaW5jaGVzPUYsYWRkPVQpCn0KYGBgCgpJbXBvcnRhbmNpYSBkZSBjYWRhIHZhcmlhYmxlIC0gdmFyaWFuemEgcG9uZGVyYWRhIHBvciBlbCB0YW1hw7FvIGRlIGxhIGNlbGRhOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBzaWdtYTIgPC0gc3FydChhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwyLGZ1bmN0aW9uKHgsZWZmZWN0aWYpCiAgICAge208LXN1bShlZmZlY3RpZiooeC13ZWlnaHRlZC5tZWFuKHgsZWZmZWN0aWYpKV4yKS8oc3VtKGVmZmVjdGlmKS0xKX0sCiAgICAgZWZmZWN0aWY9bmIpKQogIHByaW50KHNvcnQoc2lnbWEyLGRlY3JlYXNpbmc9VCkpCn0KYGBgCgojIENsdXN0ZXJpbmcKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgaGFjIDwtIG1wci5oYWMobW9kZWwsIG5iKQp9CmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMyBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTMpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0zKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDQgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz00KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNSBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTUpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz01KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNiBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTYpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz02KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDggY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz04KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9OCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDEwIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MTApCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0xMCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKICBkZi5jbHVzdGVyMDkgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT05KQogIGRmLmNsdXN0ZXIxMCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEwKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA5IDwtIHNlbGVjdChkZi5jbHVzdGVyMDksIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIxMCA8LSBzZWxlY3QoZGYuY2x1c3RlcjEwLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdLCBkaW0oZGYuY2x1c3RlcjA5KVsxXSwgZGltKGRmLmNsdXN0ZXIxMClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiwgImNsdXN0ZXIwOSIsICJjbHVzdGVyMTAiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjEwKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKICBkZi5jbHVzdGVyMDkuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOSkKICBkZi5jbHVzdGVyMTAuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIxMCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIxMC5ncm91cGVkKQpgYGAK